package com.weiya.commons.util;

import cn.hutool.core.collection.CollectionUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * LocalMapUtils
 *
 * @author 奕超
 * @date 2017/12/5
 */
public class LocalMapUtils {

    public static <K, V> Map<K, V> listAsHashMap(List<V> list, Function<V, K> function) {
        if (CollectionUtil.isEmpty(list) || Objects.isNull(function)) {
            return new HashMap<>(0);
        }
        Map<K, V> resultMap = new HashMap<>(list.size());
        for (V v : list) {
            if (Objects.nonNull(v)) {
                K key = function.apply(v);
                if (key != null) {
                    resultMap.put(key, v);
                }
            }
        }
        return resultMap;
    }

    public static <K, V, T> Map<K, V> listAsHashMap(List<T> list, Function<T, K> keyFunction,
            Function<T, V> valueFunction) {
        if (CollectionUtil.isEmpty(list) || Objects.isNull(keyFunction) || Objects.isNull(valueFunction)) {
            return new HashMap<>(0);
        }
        Map<K, V> resultMap = new HashMap<>(list.size());
        for (T t : list) {
            if(Objects.isNull(t)) {
                continue;
            }
            K key = keyFunction.apply(t);
            if (Objects.nonNull(key)) {
                V value = valueFunction.apply(t);
                if (Objects.nonNull(value)) {
                    resultMap.put(key, value);
                }
            }
        }
        return resultMap;
    }

    public static <K, V> Map<K, List<V>> listAsHashMapList(List<V> list, Function<V, K> function) {
        if (Objects.isNull(function) || CollectionUtil.isEmpty(list)) {
            return new HashMap<>(0);
        }
        HashMap<K, List<V>> resultMap = new HashMap<>(list.size());
        for (V v : list) {
            if(Objects.isNull(v)) {
                continue;
            }
            K key = function.apply(v);
            if (Objects.isNull(key)) {
                continue;
            }
            List<V> vList = resultMap.get(key);
            if (Objects.isNull(vList)) {
                vList = new ArrayList<>();
            }
            vList.add(v);
            resultMap.put(key, vList);
        }
        return resultMap;
    }

    /**
     * collection转map（value值为列表值本身；遇到重复key，覆盖旧value） 采用java 8 removeIf和stream实现
     *
     * @param collection 源列表
     * @param function 函数：获取key
     * @param <K> key    泛型
     * @param <V> value  泛型
     * @return map
     */
    public static <K, V> Map<K, V> collectionToMap(Collection<V> collection, Function<V, K> function) {
        return collectionToMap(collection, function, true);
    }

    /**
     * collection转map（value值为列表值本身）
     *
     * @param collection 源列表
     * @param function 函数：获取key
     * @param isCover 遇到重复key，是否覆盖旧value
     * @param <K> key    泛型
     * @param <V> value  泛型
     * @return map
     */
    public static <K, V> Map<K, V> collectionToMap(Collection<V> collection, Function<V, K> function, Boolean isCover) {
        return collectionToMap(collection, function, Function.identity(), isCover);
    }

    /**
     * collection转map(遇到重复key，覆盖旧value)
     *
     * @param collection 源列表
     * @param keyFunction 函数：获取key
     * @param valueFunction 函数：获取value
     * @param <T> collection值 泛型
     * @param <K> key    泛型
     * @param <V> value  泛型
     * @return map
     */
    public static <K, V, T> Map<K, V> collectionToMap(Collection<T> collection, Function<T, K> keyFunction,
            Function<T, V> valueFunction) {
        return collectionToMap(collection, keyFunction, valueFunction, true);
    }

    /**
     * collection转map
     *
     * @param collection 源列表
     * @param keyFunction 函数：获取key
     * @param valueFunction 函数：获取value
     * @param isCover 遇到重复key，是否覆盖旧value
     * @param <T> collection值 泛型
     * @param <K> key    泛型
     * @param <V> value  泛型
     * @return map
     */
    public static <K, V, T> Map<K, V> collectionToMap(Collection<T> collection, Function<T, K> keyFunction,
            Function<T, V> valueFunction, Boolean isCover) {
        boolean cover = Objects.isNull(isCover) || isCover;
        if (CollectionUtil.isEmpty(collection) || Objects.isNull(keyFunction) || Objects.isNull(valueFunction)) {
            return new HashMap<>(0);
        }
        return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(keyFunction, valueFunction, (v1, v2) -> cover ? v2 : v1));
    }

    /**
     * collection分组
     *
     * @param collection 源列表
     * @param classifier 分类器
     * @param <K> key    泛型
     * @param <T> collection值 泛型
     * @return collectionMap
     */
    public static <K, T> Map<K, List<T>> collectionGroupBy(Collection<T> collection, Function<T, K> classifier) {
        return collectionGroupBy(collection, classifier, Collectors.toList());
    }

    /**
     * collection分组
     *
     * @param collection 源列表
     * @param classifier 分类器
     * @param <K> key    泛型
     * @param <T> collection值 泛型
     * @param <V> 每组类型泛型
     * @return collectionMap
     */
    public static <K, T, V> Map<K, V> collectionGroupBy(Collection<T> collection, Function<T, K> classifier,
            Collector<T, ?, V> downstream) {
        if (CollectionUtil.isEmpty(collection) || Objects.isNull(classifier)) {
            return new HashMap<>(0);
        }
        return collection.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(classifier, downstream));
    }

    /**
     * collection分区
     *
     * @param collection 源列表
     * @param predicate 断言
     * @param <T> collection值 泛型
     * @return 布尔分区map
     */
    public static <T> Map<Boolean, List<T>> collectionPartitionBy(Collection<T> collection, Predicate<? super T> predicate) {
        return collectionPartitionBy(collection, predicate, Collectors.toList());
    }

    /**
     * collection分区
     *
     * @param collection 源列表
     * @param predicate 断言
     * @param <T> collection值 泛型
     * @param <V> 每组类型
     * @return 布尔分区map
     */
    public static <T, V> Map<Boolean, V> collectionPartitionBy(Collection<T> collection, Predicate<? super T> predicate,
            Collector<T, ?, V> downstream) {
        if (CollectionUtil.isEmpty(collection) || Objects.isNull(predicate)) {
            return new HashMap<>(0);
        }
        return collection.stream().filter(Objects::nonNull).collect(Collectors.partitioningBy(predicate, downstream));
    }
}
